﻿namespace Webinator.MultipleAttribute
{
    using System.Collections.Generic;
    using Enums;

    using Webinator.Toolboxes;

    /// <summary>
    /// Multiple attribute <c>Locator</c> builder.
    /// </summary>
    public class DefinedAttributes
    {
        /// <summary>
        /// The attributes.
        /// </summary>
        private List<DefineAttribute> _attributes;

        /// <summary>
        /// Gets or sets the attributes.
        /// </summary>
        internal List<DefineAttribute> Attributes
        {
            get { return _attributes ?? (_attributes = new List<DefineAttribute>()); }
            set { _attributes = value; }
        }

        /// <summary>
        /// Find by attribute exists.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndExists(string attribute)
        {
            Attributes.Add(new DefineAttribute(attribute));
            return this;
        }

        /// <summary>
        /// Find by attribute exists.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrExists(string attribute)
        {
            var attr = new DefineAttribute(attribute);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by any attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndAny(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Any, value, contains));
            return this;
        }

        /// <summary>
        /// Find by any attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrAny(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Any, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>alt</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndAlt(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Alt, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>alt</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrAlt(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Alt, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>class</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndClass(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Class, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>class</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrClass(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Class, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }
        
        /// <summary>
        /// Find by a custom attribute.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndCustom(string attribute, string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(attribute, value, contains));
            return this;
        }

        /// <summary>
        /// Find by a custom attribute.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrCustom(string attribute, string value, bool contains = false)
        {
            var attr = new DefineAttribute(attribute, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>href</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndHref(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Href, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>href</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrHref(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Href, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>id</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndId(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Id, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>id</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrId(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Id, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>name</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndName(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Name, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>name</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrName(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Name, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>src</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndSrc(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Src, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>src</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrSrc(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Src, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>style</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndStyle(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Style, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>style</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrStyle(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Style, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the inner text.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndText(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Text, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the inner text.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrText(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Text, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>type</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndType(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Type, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>type</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrType(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Type, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        /// <summary>
        /// Find by the <c>value</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes AndValue(string value, bool contains = false)
        {
            Attributes.Add(new DefineAttribute(AttributeIs.Value, value, contains));
            return this;
        }

        /// <summary>
        /// Find by the <c>value</c> attribute.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="contains">Indicates whether the attribute value should be an exact match.</param>
        /// <returns>
        /// The attribute to use in the <c>Locator</c>.
        /// </returns>
        public DefinedAttributes OrValue(string value, bool contains = false)
        {
            var attr = new DefineAttribute(AttributeIs.Value, value, contains);
            attr.Or = true;
            Attributes.Add(attr);
            return this;
        }

        public string Xpath()
        {
            return XPathToolbox.GetXpathFromDefinedAttributes(this);
        }
    }
}